package showtime.framework.engine.map.rpg
{
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import showtime.framework.engine.Entity2D;
	import showtime.framework.engine.Group2D;
	import showtime.framework.engine.IEntity;
	import showtime.framework.engine.map.MapEventType;
	import showtime.framework.engine.map.MapLayerType;


	public class RPGGameMap extends Sprite implements IEntity
	{							
		/**
		 * Map mask layer. 
		 */		
		private var maskLayer:Shape = null;
		
		private var collisionLayer:MapLayer = null;		
		private var tileLayer:MapLayer = null;	

		private var defaultGroup:Group2D = null;		
		private var eventGroup:Group = null;
		
		public var objectGroup:Group = null;
		public var objectLayer:Sprite = null;
		
		public var active:Boolean = false;
		
		public var camera:Point = null;		
		/**
		 * The visible Area of the map component. 
		 */		
		public var visibleWidth:int = 0;
		public var visibleHeight:int = 0;
		
		/**
		 * The buffer which cache the map tile image. 
		 */		
		public var buffer:BitmapData = null;
		/**
		 * Pre load tile amounts. 
		 */		
		public var preloadX:int = 0;
		
		public var preloadY:int = 0;
		
		public var visibleRec:Rectangle = null;
		/**
		 *   Follow target.
		 */		
		public var target:* = null;
		/**
		 * Constructor.
		 *  
		 * @param visibleWidth
		 * @param visibleHeight
		 * @param layers
		 * @param buffer
		 * @param preloadX
		 * @param preloadY
		 * 
		 */		
		public function RPGGameMap(visibleWidth:int, visibleHeight:int, layers:Array, groups:Array, buffer:BitmapData, preloadX:int , preloadY:int)
		{
			this.active = true;
			this.buffer = buffer;
			this.visibleHeight = visibleHeight;
			this.visibleWidth = visibleWidth;
			this.visibleRec = new Rectangle();
			
			this.camera = new Point();
			
			this.preloadX = preloadX;
			this.preloadY = preloadY;

			defaultGroup = new Group2D();
			
			maskLayer = new Shape();
			maskLayer.graphics.beginFill(0xFFFFFF);
			maskLayer.graphics.drawRect(0, 0, visibleWidth, visibleHeight);
			maskLayer.graphics.endFill();
			mask = maskLayer;			
			
			for each (var layer:MapLayer in layers)
			{
				if (layer.type == MapLayerType.TILE)
				{
					tileLayer = layer;
					tileLayer.register(this);
				}
				else if (layer.type == MapLayerType.COLLISION)
				{
					collisionLayer = layer;					
				}
				
			}
			
			objectLayer = new Sprite();
			addChild(objectLayer);			
			
			for each (var group:Group in groups)
			{
				if (group.name == MapLayerType.EVENT)
				{
					eventGroup = group;
				}
				else if (group.name == MapLayerType.OBJECT)
				{
					objectGroup = group;
				}
			}

		}
		
		public function destroy():void
		{	
			tileLayer.destroy();			
			collisionLayer.destroy();			
			defaultGroup.destroy();
			
			buffer = null;			
			target = null;			
			
			active = false;
		}
		
		public function update():void
		{
			defaultGroup.update();			
			
			tileLayer.update();
			
		}
		
		public function render():void
		{
//			var startX:int = camera.x - 4 < 0 ? 0 : camera.x - 4;
//			var startY:int = camera.y - 4 < 0 ? 0 : camera.y - 4;
//			
//			var endX:int = camera.x + 4 > visibleWidth ? visibleWidth : camera.x + 4;
//			var endY:int = camera.y + 4 > visibleHeight ? visibleHeight : camera.y + 4;
//			
//			visibleRec.x = startX;
//			visibleRec.y = startY;
//			visibleRec.width = endX;
//			visibleRec.height = endY;
//			for each (var object:Object in defaultGroup.members)
//			{
//				var xx:int = object.x / 32;
//				var yy:int = object.y / 32
//				if (!visibleRec.contains(xx, yy))
//				{
//					object.visible = false;
//				}
//				else
//				{
//					object.visible = true;
//				}
//			}
			
			defaultGroup.render();
			tileLayer.render();
		}
		
		public function addObect(object:*):void
		{
			defaultGroup.addEntity(object);
			objectLayer.addChild(object);
		}
		
		/**
		 * 从地图对象层移除一个单元。
		 *  
		 * @param item
		 * 
		 */		
		public function removeObject(entity:Entity2D):void
		{
			defaultGroup.removeEntity(entity, true).destroy();
		}
		/**
		 * 设置摄像头跟随目标。
		 * 
		 */		
		public function follow(target:Object):void
		{
			this.target = target;
			
			addObect(target);
			
			update();
			
			render();
		}
			
		public function hitObject(point:Point):Boolean
		{
			var testObject:Object = null;

			for each (var object:Object in defaultGroup.members)
			{
				if ((object.x == point.x) && (object.y == point.y))
				{
					testObject = object;
					break;
				}
			}
			
			if (testObject != null && testObject.source.solid)
			{
				return true;
			}
			
			return false;
		}
		
		public function getObjectByID(id:String):Object
		{
			for each (var object:Object in defaultGroup.members)
			{
				if (object.source.id == id)
				{
					return object;
				}
			}
			
			return null;
		}
		
		public function getObjectByName(name:String):Object
		{
			for each (var object:Object in defaultGroup.members)
			{
				if (object.source.name == name)
				{
					return object;
				}
			}
			
			return null;
		}
		
		public function getObjectByTarget(target:Object):Object
		{
			var point:Point = target.getNowPoint();
			for each (var object:Object in defaultGroup.members)
			{
				if ((object.x == point.x) && (object.y == point.y) && object != target)
				{
					return object;
				}
			}
			
			return null;
		}
		
		public function getObjectsByPoint(point:Point):Array
		{
			var result:Array = [];
			for each (var object:Object in defaultGroup.members)
			{
				if ((object.x == point.x) && (object.y == point.y))
				{
					result.push(object);
				}
			}
			
			return result;
		}
		
		public function getObjectByPoint(point:Point):Object
		{
			for each (var object:Object in defaultGroup.members)
			{
				if ((object.x == point.x) && (object.y == point.y))
				{
					return object;
				}
			}
			
			return null;
		}
		
		
		public function getEvent(point:Point):ObjectHolder
		{
			if (eventGroup == null)
			{
				return null;
			}
			
			for each (var event:ObjectHolder in eventGroup.objects)
			{					
				if (event.type == MapEventType.TRANSFER)
				{
					var expression:String = event.properties["expression"];
					var conditions:Array = String(event.properties["conditions"]).split(",");
					var isSatisfaction:Boolean = true;
					var condition:String = null;
					switch (expression)
					{
						case "EQ":
						{						
							for each (condition in conditions)
							{
								if (event[condition] != point[condition])
								{
									isSatisfaction = false;
									break;
								}
							}
							
							break;							
						}
						case "LE":
						{
							for each (condition in conditions)
							{
								if (point[condition] > event[condition])
								{
									isSatisfaction = false;
									break;
								}
							}
							
							break;
						}
						case "GE":
						{
							for each (condition in conditions)
							{
								if (point[condition] < event[condition])
								{
									isSatisfaction = false;
									break;
								}
							}
							
							break;
						}							
						
					}	
					
					if (isSatisfaction)
					{
						return event;
					}
				}
				else if (event.x == point.x && event.y == point.y)
				{
					return event;
				}
				
			}
			
			return null;
		}
		
		public function collisionCode(point:Point):int
		{
			if (collisionLayer == null)
			{
				return 0;
			}
		
			return collisionLayer.data[tileLayer.layerWidth * int(point.y / tileLayer.tileWidth) + int(point.x / tileLayer.tileHeight)];
		}
	}
}